package com.mezz.bones.framework.core.strategy;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.StrFormatter;
import com.mezz.bones.framework.base.domain.enums.ResponseCode;
import com.mezz.bones.framework.base.exception.BaseException;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.Map;

/**
 * @description:
 * 策略模式上下文/代理
 * ApplicationContextAware 可注入applicationContext 上下文对象
 *
 * 设计模式(策略 抽象工厂)
 */
@Service
public class StrategyContext implements CommandLineRunner {

  @Resource
  private ApplicationContext applicationContext;

  private Map<String, IStrategy> strategies;  // 使用 String 作为 Map 的键

  /**
   * @description 客户端使用入口
   * @param strategyType 策略抽象接口的类型
   * @param tag 策略对象业务标识符
   */
  public <S extends IStrategy> S getStrategy(Class<S> strategyType, String tag) {

    String key = strategyType.getName() + "-" + tag;  // 生成的key与策略实现类中的uniqueTag保持一致
    S result = strategyType.cast(strategies.get(key));
    if (result == null) {
      throw new BaseException(ResponseCode.STRATEGY_NOT_FOUND,StrFormatter.format(
              "未找到策略对象 class: [{}] tag: [{}],请联系管理员!",
              strategyType.getName(), tag));
    }
    return result;
  }


  @Override
  public void run(String... args) throws Exception {
    // 初始化所有的策略对象
    Collection<IStrategy> iStrategies = applicationContext.getBeansOfType(IStrategy.class).values();
    strategies = MapUtil.newHashMap(iStrategies.size());
    for (IStrategy strategy : iStrategies) {
      strategies.put(strategy.uniqueTag(), strategy);
    }
  }
}
